﻿using UnityEditor;
using UnityEngine;
using System.Linq;
public class FixAnimationByPath : EditorWindow
{
    /// <summary>
    /// 需要改变的物体
    /// </summary>
    private GameObject target;
    /// <summary>
    /// 失效的AnimationClip
    /// </summary>
    private AnimationClip ac;

    private Vector2 acControllerScrollPos = Vector2.zero;
    private EditorCurveBinding[] bindings;
    private EditorCurveBinding[] originBindings;
    private GameObject[] objs;

    [MenuItem("工具/动画修复/Animation")]
    static void FixAnimationByPathMethod()
    {
        Rect wr = new Rect(0, 0, 500, 500);
        FixAnimationByPath window = (FixAnimationByPath)EditorWindow.GetWindowWithRect(typeof(FixAnimationByPath), wr, true, "Fix Animation");
        window.Show();
    }

    GameObject FindInChildren(GameObject obj, string goName)
    {
        Transform objTransform = obj.transform;
        Transform findedTransform = objTransform.Find(goName);

        GameObject finded;
        if (findedTransform == null)
        {
            for (int i = 0; i < objTransform.childCount; ++i)
            {
                finded = FindInChildren(objTransform.GetChild(i).gameObject, goName);
                if (finded)
                {
                    return finded;
                }
            }
            return null;
        }
        return findedTransform.gameObject;
    }
    
    private GameObject GetBindingGameObject(EditorCurveBinding binding)
    {
        if(target == null || binding == null)
            return null;
        UnityEngine.Object obj = AnimationUtility.GetAnimatedObject(target, binding);
        if (obj != null)
        {
            if (obj is GameObject)
                return obj as GameObject;
            else if (obj is Transform)
                return (obj as Transform).gameObject;
            else if (obj is Component)
                return (obj as Component).gameObject;
            else
            {
                Debug.Log("no found class");
                return null;
            }
        }
        return null;
    }
    void OnGUI()
    {

        EditorGUILayout.LabelField("TargetRoot");
        target = EditorGUILayout.ObjectField(target, typeof(GameObject), true) as GameObject;

        using (var check = new EditorGUI.ChangeCheckScope())
        {
            EditorGUILayout.LabelField("AnimationClip");

            ac = EditorGUILayout.ObjectField(ac,typeof(AnimationClip), true) as AnimationClip;
            if (check.changed)
            {
                if (ac != null)
                {
                    bindings = AnimationUtility.GetCurveBindings(ac);
                    originBindings = bindings.ToArray();
                    objs = new GameObject[bindings.Length];
                    for(int i=0;i<bindings.Length;i++)
                    {
                        objs[i] = GetBindingGameObject(bindings[i]);
                    }
                }
            }
        }

        if (ac != null&&target!=null)
        {

            using (new EditorGUI.IndentLevelScope())
            using (var scroll = new EditorGUILayout.ScrollViewScope(acControllerScrollPos, new GUIStyle(), new GUIStyle("verticalScrollbar")))
            {
                acControllerScrollPos = scroll.scrollPosition;
                using (new EditorGUILayout.HorizontalScope())
                using (new EditorGUILayout.VerticalScope())
                {
                    EditorGUILayout.LabelField("Bindings", EditorStyles.boldLabel);
                    for (int i = 0; i < bindings.Length; i++)
                    {

                        using (new EditorGUILayout.HorizontalScope())
                        {
                            using (var check1 = new EditorGUI.ChangeCheckScope())
                            {
                                objs[i] = EditorGUILayout.ObjectField(objs[i], typeof(GameObject), true) as GameObject;
                                if(check1.changed)
                                {
                                    if(objs[i]!=null)
                                        bindings[i].path = AnimationUtility.CalculateTransformPath(objs[i].transform, target.transform);
                                }
                            }
                            using (var check2 = new EditorGUI.ChangeCheckScope())
                            {
                                bindings[i].path = EditorGUILayout.TextField(bindings[i].path, EditorStyles.textField);
                                if (check2.changed)
                                {
                                    objs[i] = GetBindingGameObject(bindings[i]);
                                }
                            }
                        }

                    }
                }


            }
        }
        using (new EditorGUI.DisabledGroupScope(!target || !ac))
        {
            using (new EditorGUILayout.HorizontalScope())
            {
                //开启可能会选取到错误的GameObject
                if (GUILayout.Button("Use Object Name"))
                {
                    for (int i = 0; i < bindings.Length; i++)
                    {
                        string[] subPath = bindings[i].path.Split('/');
                        if (subPath.Length > 0) bindings[i].path = subPath[subPath.Length - 1];
                    }
                }
                if (GUILayout.Button("Find Object"))
                {
                    for (int i = 0; i < bindings.Length; i++)
                    {
                        if (objs[i]!=null)
                        {
                            GameObject obj = GetBindingGameObject(bindings[i]);
                            if (obj == null) obj = FindInChildren(target, bindings[i].path);
                            objs[i] = obj;
                        }
                    }
                }
            }
            if (GUILayout.Button("Fix"))
            {
                for (int i = 0; i < originBindings.Length; i++)
                {
                    if (objs[i] == null) continue;
                    string newPath = AnimationUtility.CalculateTransformPath(objs[i].transform, target.transform);
                    AnimationCurve curve = AnimationUtility.GetEditorCurve(ac, originBindings[i]);

                    AnimationUtility.SetEditorCurve(ac, originBindings[i], null);
                    bindings[i].path = newPath;
                    AnimationUtility.SetEditorCurve(ac, bindings[i], curve);
                }
            }
        }
    }
}